home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac100% 1998 November
/
MAC100-1998-11.ISO.7z
/
MAC100-1998-11.ISO
/
オンラインソフト定点観測
/
ユーティリティ
/
Mops 3.2.sea
/
Mops 3.2
/
Mops source
/
PPC source
/
zFloating point
< prev
next >
Wrap
Text File
|
1998-04-29
|
19KB
|
823 lines
¥ Mar 98 mrh Initial PowerPC version.
:f fNum? false ;f
syscall dec2num
syscall num2dec
syscall dec2str
syscall str2dec
$ BD42 simple_op SF@
$ BD43 simple_op SF!
8 constant 1FLOAT
¥ Our default float is an IEEE double. Thus DF@ etc. are aliases for F@ etc.
: DF@ inline{ f@} ;
: DF! inline{ f!} ;
¥ SF@ and SF! are in pnuc1.
: FLOAT+ inline{ 8 +} ;
: FLOAT- inline{ 8 -} ;
: FLOATS inline{ 3 <<} ;
: FALIGN align8 ;
: FALIGNED #align8 ;
: DFLOAT+ inline{ 8 +} ;
: DFLOAT- inline{ 8 -} ;
: DFLOATS inline{ 3 <<} ;
: DFALIGN align8 ;
: DFALIGNED #align8 ;
: SFLOAT+ inline{ 4 +} ;
: SFLOAT- inline{ 4 -} ;
: SFLOATS inline{ 2 <<} ;
: SFALIGN align4 ;
: SFALIGNED #align4 ;
: F, ( F: r -- )
falign DP f! 1float ++> DP ;
: FVARIABLE
falign variable ;
¥ =====================================
¥ FP mode setting
¥ =====================================
¥ rounding modes:
enum{ roundToNearest roundToZero roundUp roundDown }
:ppc_code (fpscr)
fr0 mffs,
fr0 0 r4 stfd,
blr,
;ppc_code
:ppc_code (>fpscr)
fr0 0 r4 lfd,
$ FF fr0 mtfsf,
blr,
;ppc_code
: FPSCR
ftemp (fpscr) 4+ @
;
: >FPSCR
ftemp 4+ ! ftemp (>fpscr) drop ;
: rounding_mode
fpscr 3 and ;
: >rounding_mode
3 and fpscr $ ffffffc0 and or >fpscr ;
¥ =====================================
¥ Rounding to integer
¥ =====================================
variable 2**52 4 reserve
variable -2**52 4 reserve
$ 43300000 2**52 !
$ C3300000 -2**52 !
: round { %x ¥ %bias -- %x' }
%x f0>=
IF ¥ positive - add 2**52, then subtract it
2**52 f@ -> %bias
%x %bias f>
IF %x EXIT THEN
ELSE
-2**52 f@ -> %bias
%x %bias f<
IF %x EXIT THEN
THEN
%x %bias f+ %bias f-
;
: FLOOR
fpscr
roundDown >rounding_mode
round
>fpscr
;
: FROUND
fpscr
roundToNearest >rounding_mode
round
>fpscr
;
¥ =====================================
¥ FP to/from decimal conversion
¥ =====================================
¥ Some useful constants:
256 constant NEG
0 constant POS
1 constant fixedDecimal
0 constant floatDecimal
¥ Our DEC class combines the SANE/MathLib decimal and decform records,
¥ and adds appropriate methods to do what we want. We could equally
¥ well have made these two separate classes, but this is a little
¥ less complicated, especially as we only instantiate one Dec object.
:class DEC super{ object }
public
¥ decimal record ( x = (-1)^sgn * 10^exp * digits )
record
{
byte sign
byte unused
int exp ¥ offs 2
ubyte length ¥ offs 4
36 bytes text ¥ PPC Numerics manual sez 36 is the max len
ubyte unused1
uint index ¥ offs 42 - used by the scanner
¥ decform record starts here (we're aligned, at offs 44)
byte style
byte unused2
int #digits ¥ # of sig digits, if float;
¥ # dec. places, if fixed.
int valid? ¥ used by the scanner.
}
:m CLEAR:
addr: sign 41 erase ;m
:m EINIT: clear: self FloatDecimal put: style 19 put: #digits ;m
:m FINIT: clear: self FixedDecimal put: style ;m
:m SETSTYLE: put: style ;m
:m SET#DIGITS: put: #digits ;m
:m SETEXP: put: exp ;m
:m EXP: get: exp ;m
:m SIGN: get: sign ;m
:m ZERO: ¥ Puts a "0" in decimal record (length 1)
clear: self $ 0130 addr: length w! ;m
:m FLOAT: ( -- d )
^base ¥ Addr of decimal record
dec2num ¥ returns a double
;m
¥ >DEC: converts the passed-in double float to decimal.
:m >DEC:
addr: style ¥ addr of decform record
¥ (double is on top of FP stack)
^base ¥ Addr of decimal record
num2dec
;m
¥ Ascii input
:m $>DEC: ¥ ( addr len -- )
str255 1+
clear: index addr: index
^base addr: valid?
str2dec ;m
:m $>DEC?: { addr len -- b }
¥ Attempts to convert the passed-in string, using $>DEC:.
¥ Returns True if all the input was read. Otherwise
¥ we assume the terminating (non-scanned) character is
¥ invalid, and return False.
addr len $>dec: self
get: valid? 0<> ¥ turn a C flag into a Mops one
;m
¥ Ascii output
:m FORMAT: { ¥ addr ^c -- addr' len }
pad -> addr ¥ as good a place as any for the output
addr: style ¥ addr of decform
^base ¥ addr of decimal record
addr
dec2str
addr -> ^c
BEGIN ^c c@ WHILE 1 ++> ^c REPEAT
addr ^c addr - ;m
:m PRINT:
format: self type ;m
:m DUMP:
." sign: " get: sign IF & - ELSE & + THEN emit cr
." exp: " print: exp cr
addr: length count type cr
." style: " get: style IF ." fixed" ELSE ." float" THEN cr
." index: " get: index . cr
." #digits: " get: #digits . cr ;m
;class
dec theDec
: #DIGITS set#digits: theDec ;
: E.R ( F: r -- ) { wid ¥ svOut -- }
out -> svOut
floatDecimal setStyle: theDec
wid 6 - #digits ¥ Allow for point, sign, and e+nn
>dec: theDec
print: theDec
wid out svOut - - spaces ;
: E. ( F: r -- ) 23 e.r ; ¥ 64-bit double gives us a 52-bit
¥ fraction, or 17 decimal digits of
¥ significance.
: FS. inline{ e.} ; ¥ ANSI synonym.
: F.R ( F: r -- ) { wid ¥ #dig svOut -- }
out -> svOut
floatDecimal setStyle: theDec
wid 2- #digits ¥ Allow for sign and dec point
>dec: theDec
fixedDecimal setStyle: theDec
exp: theDec negate dup -> #dig #digits
sign: theDec NIF space THEN
#dig NIF space THEN ¥ In this case, no dec point
print: theDec
wid out svOut - - spaces ;
: F. ( F: r -- ) ¥ Default fixed-point format print.
19 f.r ; ¥ 17 digits of precision, plus the "." and the
¥ trailing space gives a field width of 19.
: REPRESENT { addr len %x -- exp sign ok? }
¥ ANSI word to give a generic ASCII representation for
¥ a floating point number. The fraction, rounded to len
¥ digits, is placed at addr (using round to nearest rounding).
¥ Returns the exponent (assuming the decimal point is just to
¥ the left of the fraction), the sign (true = minus) and
¥ a success/failure flag.
fpscr
roundToNearest >rounding_mode
len #digits
%x >dec: theDec
>fpscr
exp: theDec get: ivar> length in theDec +
sign: theDec
addr: ivar> text in theDec dup c@
& 0 & 9 within? nip
IF addr len cmove true
ELSE drop addr len & * fill false
THEN
;
(* >FLOAT Attempts to convert the passed-in ASCII string to
floating, if possible. On success, returns true on the data
stack and the floating number on the FP stack. On failure,
returns false on the data stack.
The ANSI standard defines this word to be very liberal - I think
it's more liberal than str2dec in MathLib. So eventually we
might have to add a preprocessing scan on the input string.
But as it stands it will work for any reasonable-looking number.
*)
: >FLOAT { addr len -- b } ( F: -- r | -- )
¥ Converts the passed-in ASCII string to
¥ floating, if possible. On success, returns
¥ true on the data stack and the floating number
¥ on the FP stack. On failure, returns false
¥ on the data stack.
addr len $>dec?: thedec NIF false EXIT THEN
float: theDec true ;
¥ ==============================
¥ Interpretation
¥ ==============================
: FNUMBER ¥ ( addr -- flt T | -- F )
¥ Attempts to convert token at addr to a float.
count >float ;
: FLITERAL ( F: r -- ) ¥ Compiles an in-line float.
ftemp f! ¥ store float at ftemp
const_data_ref postpone f@ ¥ compile fetch from const_data area
ftemp 8 add: const_data ¥ store the float in this defn's
¥ const_data
; immediate
(* FNUM? is called from INTERPRET, to check if the string at addr
is a FP number. ANSI specifies that it's a float if it contains
"E" and the base is decimal. As well as this, Mops has always
taken an embedded decimal point to indicate a float, if floating
point is loaded. So we do all these here. We assume it's a
float if we're in decimal, and the string contains E, e, or a
decimal point.
If these conditions are met but fNumber returns an error, we
give a "not found" error, since at this point INTERPRET has already
looked in the dictionary for the string and not found it, and
if it contains E or . then it certainly isn't a legal integer.
*)
:f FNUM? { addr ¥ addr' len -- T | -- addr F } ( F: -- r | -- )
base 10 <> IF addr false EXIT THEN
addr count -> len -> addr'
addr' len & . scan nip
NIF addr' len & E scan nip
NIF addr' len & e scan nip
NIF
addr false EXIT
THEN
THEN
THEN
addr fnumber ?notFound
state IF postpone fliteral THEN true ;f
¥ FP stack dump:
: dummy ;
: F.S { ¥ start-addr end-addr ¥ val dpth -- }
0.0 0.0 dummy ¥ push off the 2 cells in regs
0 -> out
fsp -> start-addr fsp0 -> end-addr
start-addr end-addr >
IF ." underflow" cr f2drop EXIT THEN
start-addr end-addr =
IF ." empty" cr f2drop EXIT THEN
end-addr start-addr - 3 a>> -> dpth
." depth " dpth .
BEGIN
¥ ?pause
cr
start-addr f@ e.
8 ++> start-addr
start-addr end-addr >=
UNTIL
cr f2drop
;
¥ F.S+ does our FP stack display in the Mops window. It's forward
¥ defined, and initially resolved to a dummy word which does nothing.
¥ Here we re-resolve it. It's called from the DS: method in
¥ class TEFwind.
:f F.S+
getbotx: tempRect 2/ negate 0 setOrigin
10 10 gotoxy ." FP stack: "
f.s
0 0 setOrigin
;f
¥ ===========================================
¥ Integer <-> FP conversions
¥ ===========================================
(* The algorithm here looks a bit magic, but isn't really complicated.
The initial problem is the different way we represent negative
numbers in FP and integer arithmetic. For a single (4-byte) integer,
we first bias the integer by flipping the top bit. This converts
the 2's complement integer to an an unsigned integer biassed by
2**31.
We now convert this to FP by prepending another 32-bit word
which contains just the exponent. To get this exponent, remember
that if the binary point is straight after the exponent (just
before bit 12) the biassed exponent is 1023 (see the manual).
So moving the binary point down to the integer position, before
the (imaginary) bit 64, we get an exponent of
1023+64-12 = 1024+51 = $433.
Now the new FP number has an implicit leftmost 1 in the (52-bit)
fraction part, so in doing this we've in effect added another
bias of 2**52. All we then have to do is load this into an FPR,
and subtract the total bias, which at the same time normalizes
the result for us. The total bias is 2**52 + 2**31. In FP,
this is a number with the same exponent as above ($433), and
a 1 in bit 32 (the 2**52 is again implicit). This is the number
"fmagic" below.
For converting a double integer to floating, we do the equivalent.
THe Forth Standard says it's ambiguous if the number can't be
exactly represented as a float, which for us means if there are
more than 52 significant bits in the double integer. In this case,
as it's ambiguous, we can do anything we like. Our algorithm will
simply give a rounded result, which is pretty reasonable.
*)
variable fmagic 8 allot
$ 43300000 fmagic !
$ 80000000 fmagic 4+ !
variable fmagic2 8 allot
$ 45300000 fmagic2 !
$ 80000000 fmagic2 4+ !
variable fmagic3 8 allot
$ 43300000 fmagic3 !
0 fmagic3 4+ !
: S>F ( n -- ) ( f: -- r )
$ 43300000 ftemp ! ¥ Store exponent
$ 80000000 xor ¥ flip top bit of integer
ftemp 4+ ! ¥ store as lo half of FP number
ftemp f@ ¥ fetch to FP regs
fmagic f@ f- ¥ subtract FP bias
;
: D>F
$ 45300000 ftemp ! ¥ Store exponent
$ 80000000 xor ¥ flip top bit of integer
ftemp 4+ ! ¥ store as lo half of FP number
ftemp f@ ¥ fetch to FP regs
fmagic2 f@ f- ¥ subtract FP bias
$ 43300000 ftemp ! ¥ Store exponent
ftemp 4+ ! ¥ store as lo half of FP number
ftemp f@ ¥ fetch to FP regs
fmagic3 f@ f- ¥ subtract unsigned FP bias
f+ ¥ add both components
;
¥ F>D could be implemented along the lines of ROUND (see above), but
¥ with all the monkeying around with rounding modes etc, it turns out
¥ to take 4 times as many instructions as the following, which we've
¥ lifted from Metrowerks:
:ppc_code F>D
fr2 -8 rRP stfd,
fr2 fr1 fmr,
fr1 0 rFSP lfd,
rFSP rFSP 8 addi,
r3 -4 rSP stw,
r4 -8 rSP stwu,
r4 -8 rRP lwz,
r3 -4 rRP lwz,
r5 r4 12 21 31 rlwinm,
r5 1023 cmpli,
lt if,
r3 0 li,
r4 0 li,
blr,
then,
r6 r4 mr,
r4 r4 0 12 31 rlwinm, ¥ mantissa has implied 1 bit
r4 r4 $ 10 oris, ¥ [nh = (nh & 0xfffff) | 0x100000]
¥ when exp-1075 < 0 we need to shift right, else shift left
r5 r5 -1075 addi,
r5 0 cmpi,
lt if,
¥ shift r3:r4 right by -exp bits
r5 r5 neg,
r8 r5 32 subfic,
r9 r5 -32 addic,
r3 r3 r5 srw,
r10 r4 r8 slw,
r3 r3 r10 or,
r10 r4 r9 srw,
r3 r3 r10 or, ¥ low word
r4 r4 r5 srw, ¥ high word
else,
¥ shift r3:r4 left by 'exp' bits
¥ if exp >= 32, then the result is undefined. later we might force
¥ this to the maximum long long value or whatever might make sense
¥ to users.
r8 r5 32 subfic,
r9 r5 -32 addic,
r4 r4 r5 slw,
r10 r3 r8 srw,
r4 r4 r10 or,
r10 r3 r9 slw,
r4 r4 r10 or, ¥ high word
r3 r3 r5 slw, ¥ low word
then,
¥ if the sign bit was set, negate the long long
r6 r6 0 0 0 rlwinm.,
eq bclr,
r3 r3 0 subfic,
r4 r4 subfze,
blr,
;ppc_code
: F>S f>d drop ;
¥ ==================================
¥ Constants
¥ ==================================
¥ 0.0 is already defined - we keep it in the register fr14.
1.0 fconstant F1.0 ¥ FSL uses this
¥ ==================================
¥ Transcendentals etc.
¥ ==================================
syscall sin
syscall cos
syscall tan
syscall asin
syscall acos
syscall atan
syscall atan2
syscall sinh
syscall cosh
syscall tanh
syscall asinh
syscall acosh
syscall atanh
syscall exp
syscall expm1
syscall pow
syscall log
syscall log1p
syscall log10
syscall sqrt
: FSIN sin ;
: FCOS cos ;
: FTAN tan ;
: FASIN asin ;
: FACOS acos ;
: FATAN atan ;
: FATAN2 atan2 ;
: FSINH sinh ;
: FCOSH cosh ;
: FTANH tanh ;
: FASINH asinh ;
: FACOSH acosh ;
: FATANH atanh ;
: FEXP exp ;
: FEXPM1 expm1 ;
: F** pow ;
: FLN log ; ¥ log to base e
: FLNP1 log1p ;
: FLOG log10 ; ¥ log to base 10
: FSQRT sqrt ;
: 1/F 1.0 fswap f/ ;
: F**2 inline{ fdup f*} ;
¥ ======================================
¥ Infinities and NANs
¥ ======================================
1.0 0.0 f/ fconstant infinity
infinity fnegate fconstant -infinity
: SNAN ( code -- ) ( F: -- NAN<code> )
8 << $ 7ff00000 or ftemp ! ftemp sf@ ;
: QNAN ( code -- ) ( F: -- NAN<code> )
8 << $ 7ff80000 or ftemp ! ftemp sf@ ;
100 sNAN fconstant UNDEF
¥ ===================================
¥ Class Float
¥ ===================================
(* Class Float allows a floating value to be a high-level object, which
means it can be an ivar or array element. In 68k Mops we included
methods like *: and /:, but as these involve storing the updated
float to memory, which is much slower on the PowerPC than doing the
operations, we're now omitting them. We just include +: and -:
for consistency with our other numeric types.
*)
:class FLOAT super{ object }
8 bytes data
:m GET: ¥ ( -- x ) Pushes private data onto FP stack
inline{ ^base f@} ;m
:m PUT: ¥ ( x -- ) Stores float into private data
inline{ ^base f!} ;m
:m ->: ¥ ( float -- ) Assigns value of passed-in Float to this Float
inline{ f@ ^base f!} ;m
¥ ----- Arithmetic operations take a stack float (not a Float obj)
:m +:
inline{ ^base f@ f+ ^base f!} ;m
:m -:
inline{ ^base f@ f- ^base f!} ;m
:m ABSVAL: ¥ ( -- abs ) Returns absolute value.
inline{ ^base f@ fabs} ;m
:m ABS: ¥ ( -- ) Replaces obj's data with its absolute. Doesn't
¥ return anything.
inline{ ^base f@ fabs ^base f!} ;m
:m NEG: ¥ ( -- val ) Returns object value with sign negated
inline{ ^base f@ fnegate} ;m
:m NEGATE: ¥ ( -- ) Negates the object's data. Doesn't return anything.
inline{ ^base f@ fnegate ^base f!} ;m
:m PRINT: ^base f@ e. ;m
;class
¥ =================================
¥ Floating arrays
¥ =================================
:class FARRAY super{ indexed-obj } 1float indexed
:m AT: ( index -- n ) inline{ ^elem f@} ;m
:m TO: ( n index -- ) inline{ ^elem f!} ;m
:m +TO: ( n index -- ) inline{ ^elem dup f@ f+ f!} ;m
:m -TO: ( n index -- ) inline{ ^elem dup f@ f- f!} ;m
:m FILL: ¥ ( value -- ) Fills all elements with value.
idxbase limit floats bounds
?DO fdup i f! 1float +LOOP fdrop ;m
:m PRINT: ¥ Prints all elements
limit: self 0 ?DO i dup 4 .r space at: self e. cr
LOOP ;m
:m CLASSINIT:
undef
limit: self FOR fdup i to: self NEXT fdrop ;m
;class
:class SFARRAY super{ indexed-obj } 4 indexed
:m AT: ( index -- n ) inline{ ^elem sf@} ;m
:m TO: ( n index -- ) inline{ ^elem sf!} ;m
:m +TO: ( n index -- ) inline{ ^elem dup sf@ f+ sf!} ;m
:m -TO: ( n index -- ) inline{ ^elem dup sf@ f- sf!} ;m
:m FILL: ¥ ( value -- ) Fills all elements with value.
idxbase limit sfloats bounds
?DO fdup i f! 4 +LOOP fdrop ;m
:m PRINT: ¥ Prints all elements
limit: self 0 ?DO i dup 4 .r space at: self e. cr
LOOP ;m
:m CLASSINIT:
undef
limit: self FOR fdup i to: self NEXT fdrop ;m
;class
¥ Fmatrix implements a 2-dimensional FP matrix.
¥ Usage: 50 100 dimension Fmatrix MM
0 value ROWDIM
0 value COLDIM
: DIMENSION
-> colDim -> rowDim
colDim rowDim * ;
:class FMATRIX super{ Farray }
var #rows
var #cols
var rowLength
var colLength
:m #ROWS: get: #rows ;m
:m #COLS: get: #cols ;m
:m ^ELEM: { row col ¥ temp -- addr }
row get: #cols * col + ^elem ;m
:m AT: ^elem: self f@ ;m
:m TO: ^elem: self f! ;m
:m ROW: { row -- limit start stride } ¥ Sets up for a DO over the row.
row get: rowLength * idxBase + ¥ addr
get: rowLength bounds ¥ ( limit addr )
1float ;m ¥ stride
:m COL: { col -- limit start stride } ¥ Sets up for a DO over the column.
col floats idxBase + ¥ addr
get: colLength bounds ¥ ( limit addr )
get: rowLength ;m ¥ stride
:m PUTROW: ¥ ( 1st ... last row -- )
row: self drop ( we know stride is 1float )
swap 1float -
DO i f! 1float negate +LOOP ;m
:m PRINTROW: { row -- }
row row: self drop
?DO i f@ 10 e.r 1float +LOOP ;m
:m PRINTCOL: { col ¥ stride -- }
col col: self -> stride
?DO i f@ 10 e.r cr stride +LOOP ;m
:m PRINT:
get: #rows 0
?DO i printRow: self cr LOOP ;m
:m CLASSINIT:
rowDim put: #rows colDim put: #cols
get: #cols floats put: rowLength
get: #rows get: rowLength * put: colLength
classinit: super ;m
;class
endload
3 5 dimension fmatrix matA
5 3 dimension fmatrix matB
3 3 dimension fmatrix matC
-2.0 -7.0 -4.0 8.0 1.0 0 putRow: matA
-3.0 0.0 -1.0 0.0 -9.0 1 putRow: matA
0.0 -1.0 -8.0 -9.0 -3.0 2 putRow: matA
-1.0 3.0 -2.0 0 putRow: matB
4.0 -1.0 1.0 1 putRow: matB
9.0 -4.0 -8.0 2 putRow: matB
-5.0 0.0 -3.0 3 putRow: matB
6.0 3.0 -6.0 4 putRow: matB